package com.itcam.avalbackend.app;


import com.itcam.avalbackend.advisor.MyLoggerAdvisor;
import com.itcam.avalbackend.chatmemory.FileBasedChatMemory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.api.Advisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

/**
 * @author : Cammy.Wu
 * Description : 
 */

@Component
@Slf4j
public class CosApp {

    private final ChatClient chatClient;

    /**
     * 系统提示语，定义了聊天机器人的角色和交互规则。
     */
    private static final String SYSTEM_PROMPT = """
            你是一位资深的 Cosplay 与漫展专家，在这个领域拥有丰富的经验和深厚的知识。你将模拟真实的 Cosplay 指导和漫展咨询场景，为用户提供专业且全面的建议，解决他们在 Cosplay 和漫展相关方面遇到的各种问题。
            当用户与你交流时，你需要做到以下几点：
            积极主动地提出引导性问题，深入了解用户的具体情况和需求。例如，询问用户喜欢的动漫角色、之前的 Cosplay 经验、对漫展的期待等。
            根据用户提供的信息，给出针对性强、实用的建议。无论是 Cosplay 服装制作、角色妆容设计，还是漫展的参展攻略、活动安排等方面，都要提供详细且有价值的内容。
            保持友好、热情的态度，让用户感受到你的专业和亲和力。
            用通俗易懂的语言进行交流，避免使用过于专业或晦涩的术语，除非用户有相关的专业背景并明确表示理解。
            当用户的问题比较宽泛或模糊时，不要急于给出答案，而是通过进一步的提问来明确问题的核心。
            以下是一些可能遇到的用户场景及回复示例：
            用户询问某个角色的 Cosplay 建议：你可以先询问用户对该角色的理解、是否有特定的版本要求等，然后再提供服装、道具、妆容等方面的建议。
            用户咨询漫展的相关信息：你可以询问用户所在的地区、感兴趣的漫展类型等，然后介绍适合的漫展以及参展的注意事项。
            通过不断与用户互动，深入了解他们的需求，你将为用户提供更加个性化、全面的服务，帮助他们在 Cosplay 和漫展的世界中获得更好的体验。
            """;

    /**
     * 构造函数，初始化聊天客户端和对话记忆。
     *
     * @param dashscopeChatModel 聊天模型，用于处理用户对话
     */
    public CosApp(@Qualifier("dashscopeChatModel") ChatModel dashscopeChatModel) {
        // 初始化基于文件的对话记忆
        Path fileDir = Paths.get(System.getProperty("user.dir"), "chat-memory");
        ChatMemory chatMemory = new FileBasedChatMemory(fileDir.toString());
        chatClient = ChatClient.builder(dashscopeChatModel)
                .defaultSystem(SYSTEM_PROMPT)
                .defaultAdvisors(
                        new MessageChatMemoryAdvisor(chatMemory)
//                        new MyLoggerAdvisor()
//                        new ReReadingAdvisor()
                )
                .build();
        log.info("CosApp 初始化完成，聊天客户端已创建");
    }

    /**
     * 处理用户的聊天请求，返回聊天响应内容。
     *
     * @param message 用户输入的消息
     * @param chatId  聊天会话的 ID
     * @return 聊天响应的文本内容
     */
    public String doChat(String message, String chatId) {
        ChatResponse response = chatClient
                .prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .chatResponse();
        String content = response.getResult().getOutput().getText();
        log.info("用户消息: {}, 聊天响应: {}", message, content);
        return content;
    }

    /**
     * 漫圈分析报告记录类，包含报告标题和建议列表。
     */
    public record CosReport(String title, List<String> suggestions) {
    }

    /**
     * 处理用户的聊天请求，并生成漫圈分析报告。
     *
     * @param message 用户输入的消息
     * @param chatId  聊天会话的 ID
     * @return 漫圈分析报告对象
     */
    public CosReport doChatWithReport(String message, String chatId) {
        CosReport cosReport = chatClient
                .prompt()
                .system(SYSTEM_PROMPT + "每次对话后都要生成漫圈分析结果，标题为{用户名}的漫圈分析报告，内容为建议列表")
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .entity(CosReport.class);
        log.info("用户消息: {}, 漫圈分析报告: {}", message, cosReport);
        return cosReport;
    }

    @Resource
    private VectorStore cosAppVectorStore;

    /**
     * 处理用户的聊天请求，并结合知识库问答返回响应内容。
     *
     * @param message 用户输入的消息
     * @param chatId  聊天会话的 ID
     * @return 结合知识库问答的聊天响应文本内容
     */
//    public String doChatWithRag(String message, String chatId) {
//        ChatResponse chatResponse = chatClient
//                .prompt()
//                .user(message)
//                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
//                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
//                // 开启日志，便于观察效果
//                .advisors(new MyLoggerAdvisor())
//                // 应用知识库问答
//                .advisors(new QuestionAnswerAdvisor(cosAppVectorStore))
//                .call()
//                .chatResponse();
//        String content = chatResponse.getResult().getOutput().getText();
//        log.info("用户消息: {}, 知识库问答响应: {}", message, content);
//        return content;
//    }

    @Resource
    private Advisor cosAppRagCloudAdvisor;

    @Resource
    private VectorStore pgVectorVectorStore;

    public String doChatWithRag(String message, String chatId) {
        ChatResponse chatResponse = chatClient
                .prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                // 开启日志，便于观察效果
                .advisors(new MyLoggerAdvisor())
                // 应用增强检索服务（云知识库服务）
//                .advisors(cosAppRagCloudAdvisor)
                // 应用RAG检索增强服务（基于PGVector向量存储）
                .advisors(new QuestionAnswerAdvisor(pgVectorVectorStore))
                .call()
                .chatResponse();
        String content = chatResponse.getResult().getOutput().getText();
        log.info("content: {}", content);
        return content;
    }
}
